package Parameters;

use vaaneeConfig qw(%C);

sub new {
	my($this) = {};
	bless $this;
	return $this;
}

sub getScore {
	my($this) = shift;
	my($Features) = shift;
	my($score) = 0;	

	foreach $feat ( keys %{$Features} )
	{
		$score += $this->{$feat} * $Features->{$feat};
	}	
	return $score;
}

sub initialize {
	my($Parameters) = shift;
	my($corpus) = shift;
	my($initialvalue) = shift;
	my($Features,$feature);

	my($i);

	foreach $i (keys %$corpus)
	{
		if($C{'trainAlgo'}>=1 && $C{'trainAlgo'}<=3) {
			$Features = $corpus->{$i}->{'SFeatures'};
			foreach $feature (keys %{$Features})
			{
				$Parameters->{$feature} = $initialvalue;
			}
		}
		elsif($C{'trainAlgo'}>=4 && $C{'trainAlgo'}<=5) {
			my($node);
			foreach $Features (@{$corpus->{$i}->{'nodeFeatures'}}) {
				foreach $feature (keys %{$Features})
				{
					$Parameters->{$feature} = $initialvalue;
				}
			}
		}
	}

}

sub list {
	my($this) = shift;
	
	foreach $param (keys %{$this})
	{
	print STDERR "$param $this->{$param}\n";
	}
}

sub average {
	my($this) = shift;
	my($denom) = shift;

	foreach $param (keys %{$this})
	{
		$this->{$param} *= 1.0/$denom;
	}
}

sub addparams {
	my($this) = shift;
	my($Parameters) = shift;
	foreach $param (keys %{$Parameters})
	{
		$this->{$param} += $Parameters->{$param};
	}
}

sub load {
	my($this) = shift;
	my($filename) = shift;
	my($param,$value);

	open(FILE,$filename) || die "Can't open -- $filename\n";
	while($line=<FILE>)
	{
		chomp($line);
		($param,$value) = split(/\s+/,$line);
		$this->{$param} = $value;
	}
	close(FILE);
}

sub copy {
	my($this) = shift;
	my($Parameters) = shift;
	
	foreach $param (keys %{$Parameters})
	{
		$this->{$param} = $Parameters->{$param};
	}
}

sub store {
	my($this) = shift;
	my($filename) = shift;
	my($param);
	
	open(FILE,">$filename");
	foreach $param (keys %{$this})
	{
		print FILE $param."\t".$this->{$param}."\n";
	}
	close(FILE);
}

sub updateParams{
	my($Parameters) = shift;
	my($goldFeatures) = shift;
	my($predictFeaturesArray) = shift;
	my($mistakesArray) = shift;
	my($numPredict) = shift;
	my(@lam_dist,@b,@dist);
	my(@GenFeatures);

	
	my $gscore = $Parameters->getScore($goldFeatures);


#	print "Updating------------------\n";
#	$goldFeatures->printLine();
#	print "\n";
#	
#	print "Scores = $gscore* , ";
	for($k=0;$k<$numPredict;$k++)
	{
		my($predscore);

#		if($k == 0)
#		{
#			print "PREDICT of 0------------------\n";
#			$predictFeaturesArray->[$k]->printLine();
#			print "END_OF_PREDICT 0------------------\n\n\n";
#		}

		$predscore = $Parameters->getScore($predictFeaturesArray->[$k]);

		my $diffFeatures;
		$diffFeatures = new Features;

		$diffFeatures->difffeatures($goldFeatures,$predictFeaturesArray->[$k]);

#		print "-- ";
#		$diffFeatures->printLine();
		
		$lam_dist[$k] = $gscore - $predscore;
#		print "$predscore($lam_dist[$k])/";
		$b[$k] = $mistakesArray->[$k];
#		print "$b[$k] ";

		$b[$k] -= $lam_dist[$k];	
	
		$dist[$k] = $diffFeatures;

		$b[$k] -= $lam_dist[$k];
	}
#	print "\n";

	@alpha = &hildreth($numPredict,\@dist,\@b);

#	print "Alpha Values : ";
#	my (%modifiedFeatures);
	for($k=0;$k<$numPredict;$k++)
	{
		$GenFeatures = $dist[$k];

#		if($k==0) {
#			print "UPDATIONS ....\n";
#			print "$alpha[$k] ";
#		}

		print STDERR "\t(Alpha: $alpha[$k])\n";
		foreach $feat (keys %$GenFeatures)
		{
			my $change;
			$change = $alpha[$k]*$GenFeatures->{$feat};
			$Parameters->{$feat} += $change;
			print STDERR "\t$feat $GenFeatures->{$feat}\n";
			if($alpha[$k]!=0 && $GenFeatures->{$feat}!=0) {
				print STDERR "\t+ $feat  $change \n" ;
			}
		}

	}
	print STDERR "\n\n";
}

sub hildreth {
	my($K) = shift;
	my($a) = shift;
	my($b) = shift;

	my($i);
	my($max_iter) = 10000;
	my($eps) = 0.00000001;
	my($zero) = 0.000000000001;

	my(@alpha,@F,@kkt);
	my($max_kkt) = -1000000;

	my(@A);
	my(@is_computed);

	for($i=0;$i<$K;$i++)
	{
		$A[$i][$i] = Features::dotProduct($a->[$i],$a->[$i]);
		$is_computed[$i] = 0;
		
		$alpha[$i]=0;
	}

	my($max_kkt_i) = -1;

	for($i=0;$i<$K;$i++)
	{
		$F[$i] = $b->[$i];
		$kkt[$i] = $F[$i];
		if($kkt[$i]>$max_kkt) { $max_kkt = $kkt[$i]; $max_kkt_i = $i; }
	}

	my($iter) = 0;
	my($diff_alpha) = 0;
	my($try_alpha) = 0;
	my($add_alpha) = 0;


	while($max_kkt >= $eps && $iter<$max_iter)
	{
		if($A[$max_kkt_i][$max_kkt_i] <= $zero)
		{
			$diff_alpha = 0.0
		}	
		else
		{
			$diff_alpha = $F[$max_kkt_i]/$A[$max_kkt_i][$max_kkt_i];
		}

		$try_alpha = $alpha[$max_kkt_i] + $diff_alpha;
		$add_alpha = 0.0;

		if($try_alpha < 0.0)
		{
			$add_alpha = -1.0 * $alpha[$max_kkt_i];
		}
		else
		{
			$add_alpha = $diff_alpha;
		}

		$alpha[$max_kkt_i] = $alpha[$max_kkt_i] + $add_alpha;

		if(!($is_computed[$max_kkt_i]))
		{
			for($i=0;$i<$K;$i++)
			{
				$A[$i][$max_kkt_i] = Features::dotProduct($a->[$i],$a->[$max_kkt_i]);
				$is_computed[$max_kkt_i] = 1;
			}
		}
		
		for($i=0;$i<$K;$i++)
		{
			$F[$i] -= $add_alpha * $A[$i][$max_kkt_i];
			$kkt[$i] = $F[$i];
			if($alpha[$i] > $zero)
			{
				if($F[$i]<0)
				{ $kkt[$i] = -$F[$i]; }
				else
				{ $kkt[$i] = $F[$i]; }
			}
		}

		$max_kkt = -100000;
		$max_kkt_i = -1;
		
		for($i=0;$i<$K;$i++)
		{
			if($kkt[$i] > $max_kkt)
			{ $max_kkt = $kkt[$i]; $max_kkt_i = $i; }	
		}

		$iter ++; 
	}

	return @alpha;
}

sub filterSyn {

	my($Parameters) = shift;
	my($synParameters);
	my($param);
	my($lhs,$rhs);

	foreach $param (%{$Parameters}) {
		if($param=~/==>/) {
			($lhs,$rhs) = split(/==>/,$param);
			$synParameters->{$lhs}->{$rhs} = $Parameters->{$param};
		}	
	}
	
	return $synParameters;
}

1;
